#pragma once

#include <string>
#include <cassert>

template<typename T, typename A = std::allocator<T> >
class XStringTemplate;

template<typename A>
class XStringTemplate<char, A> : public std::basic_string<char, std::char_traits<char>, A>
{
public:
	typedef std::basic_string<char, std::char_traits<char>, A> super_type;
	typedef char char_type;

	using super_type::operator =;
	using super_type::operator +=;
	using super_type::reserve;
	using super_type::append;

	XStringTemplate() : super_type()
	{
	}

	XStringTemplate(const char* pszStr) : super_type(pszStr)
	{
	}

	explicit XStringTemplate(size_t uLen) : super_type()
	{
		reserve(uLen);
	}

	~XStringTemplate()
	{
	}

	XStringTemplate& cat(int nValue, int nWidth = 0, BOOL bFillZero = false)
	{
		int			nRetCode	= 0;
		char_type	szFormat[8];
		char_type	szTemp[64];

		assert(nWidth >= 0);
		assert(nWidth < _countof(szTemp));

		nRetCode = snprintf(szFormat, _countof(szFormat), "%%%s%.0dd", (bFillZero ? "0" : ""), nWidth);
		assert(nRetCode > 0);

		nRetCode = snprintf(szTemp, _countof(szTemp), szFormat, nValue);
		assert(nRetCode > 0);

		append(szTemp);
		return *this;
	}

	XStringTemplate& cat(unsigned int uValue, int nWidth = 0, BOOL bFillZero = false)
	{
		int			nRetCode	= 0;
		char_type	szFormat[8];
		char_type	szTemp[64];

		assert(nWidth >= 0);
		assert(nWidth < _countof(szTemp));

		nRetCode = snprintf(szFormat, _countof(szFormat), "%%%s%.0du", (bFillZero ? "0" : ""), nWidth);
		assert(nRetCode > 0);

		nRetCode = snprintf(szTemp, _countof(szTemp), szFormat, uValue);
		assert(nRetCode > 0);

		append(szTemp);
		return *this;
	}

	XStringTemplate& cat(long long nValue, int nWidth = 0, BOOL bFillZero = false)
	{
		int			nRetCode	= 0;
		char_type	szFormat[8];
		char_type	szTemp[64];

		assert(nWidth >= 0);
		assert(nWidth < _countof(szTemp));

        nRetCode = snprintf(szFormat, _countof(szFormat), "%%%s%.0dlld", (bFillZero ? "0" : ""), nWidth);
        assert(nRetCode > 0);

		nRetCode = snprintf(szTemp, _countof(szTemp), szFormat, nValue);
		assert(nRetCode > 0);

		append(szTemp);
		return *this;
	}

	XStringTemplate& cat(unsigned long long uValue, int nWidth = 0, BOOL bFillZero = false)
	{
		int			nRetCode	= 0;
		char_type	szFormat[8];
		char_type	szTemp[64];

		assert(nWidth >= 0);
		assert(nWidth < _countof(szTemp));

        nRetCode = snprintf(szFormat, _countof(szFormat), "%%%s%.0dllu", (bFillZero ? "0" : ""), nWidth);
        assert(nRetCode > 0);

		nRetCode = snprintf(szTemp, _countof(szTemp), szFormat, uValue);
		assert(nRetCode > 0);

		append(szTemp);
		return *this;
	}

	XStringTemplate& cat(double fValue, int nWidth = 0, BOOL bFillZero = false, int nDecimal = 0)
	{
		int			nRetCode	= 0;
		char_type	szFormat[8];
		char_type	szTemp[64];

		assert(nWidth >= 0);
		assert(nWidth < _countof(szTemp));

		nRetCode = snprintf(
			szFormat, _countof(szFormat),
			"%%%s%.0d%s%.0df", (bFillZero ? "0" : ""), nWidth, (nDecimal > 0 ? "." : ""), nDecimal
		);
		assert(nRetCode > 0);

		nRetCode = snprintf(szTemp, _countof(szTemp), szFormat, fValue);
		assert(nRetCode > 0);

		append(szTemp);
		return *this;
	}

	XStringTemplate& cat(bool bValue, const char_type* pszTrue = NULL, const char_type* pszFalse = NULL)
	{
		int			nRetCode	= 0;
		char_type	szTemp[64];

		if (pszTrue == NULL)
			pszTrue = "true";

		if (pszFalse == NULL)
			pszFalse = "false";

		nRetCode = snprintf(szTemp, _countof(szTemp), "%s", (bValue ? pszTrue : pszFalse));
		assert(nRetCode > 0);

		append(szTemp);
		return *this;
	}

	XStringTemplate& cat(const char_type* pszStr)
	{
		append(pszStr);
		return *this;
	}

	XStringTemplate& operator += (XStringTemplate& other)
	{
		super_type::operator += (other.c_str());
		return *this;
	}

	template<typename U>
	XStringTemplate& operator += (U value)
	{
		return cat(value);
	}
};

template<typename A>
class XStringTemplate<wchar_t, A> : public std::basic_string<wchar_t, std::char_traits<wchar_t>, A>
{
public:
	typedef std::basic_string<wchar_t, std::char_traits<wchar_t>, A> super_type;
	typedef wchar_t char_type;

	using super_type::operator =;
	using super_type::operator +=;
	using super_type::reserve;
	using super_type::append;

	XStringTemplate() : super_type()
	{
	}

	XStringTemplate(const wchar_t* pszStr) : super_type(pszStr)
	{
	}

	explicit XStringTemplate(size_t uLen) : super_type()
	{
		reserve(uLen);
	}

	~XStringTemplate()
	{
	}

	XStringTemplate& cat(int nValue, int nWidth = 0, BOOL bFillZero = false)
	{
		int			nRetCode	= 0;
		char_type	szFormat[8];
		char_type	szTemp[64];

		assert(nWidth >= 0);
		assert(nWidth < _countof(szTemp));

		nRetCode = snwprintf(szFormat, _countof(szFormat), L"%%%s%.0dd", (bFillZero ? L"0" : L""), nWidth);
		assert(nRetCode > 0);

		nRetCode = snwprintf(szTemp, _countof(szTemp), szFormat, nValue);
		assert(nRetCode > 0);

		append(szTemp);
		return *this;
	}

	XStringTemplate& cat(unsigned int uValue, int nWidth = 0, BOOL bFillZero = false)
	{
		int			nRetCode	= 0;
		char_type	szFormat[8];
		char_type	szTemp[64];

		assert(nWidth >= 0);
		assert(nWidth < _countof(szTemp));

		nRetCode = snwprintf(szFormat, _countof(szFormat), L"%%%s%.0du", (bFillZero ? L"0" : L""), nWidth);
		assert(nRetCode > 0);

		nRetCode = snwprintf(szTemp, _countof(szTemp), szFormat, uValue);
		assert(nRetCode > 0);

		append(szTemp);
		return *this;
	}

	XStringTemplate& cat(long long nValue, int nWidth = 0, BOOL bFillZero = false)
	{
		int			nRetCode	= 0;
		char_type	szFormat[8];
		char_type	szTemp[64];

		assert(nWidth >= 0);
		assert(nWidth < _countof(szTemp));

		nRetCode = snwprintf(szFormat, _countof(szFormat), L"%%%s%.0dlld", (bFillZero ? L"0" : L""), nWidth);
		assert(nRetCode > 0);

		nRetCode = snwprintf(szTemp, _countof(szTemp), szFormat, nValue);
		assert(nRetCode > 0);

		append(szTemp);
		return *this;
	}

	XStringTemplate& cat(unsigned long long uValue, int nWidth = 0, BOOL bFillZero = false)
	{
		int			nRetCode	= 0;
		char_type	szFormat[8];
		char_type	szTemp[64];

		assert(nWidth >= 0);
		assert(nWidth < _countof(szTemp));

		nRetCode = snwprintf(szFormat, _countof(szFormat), L"%%%s%.0dllu", (bFillZero ? L"0" : L""), nWidth);
		assert(nRetCode > 0);

		nRetCode = snwprintf(szTemp, _countof(szTemp), szFormat, uValue);
		assert(nRetCode > 0);

		append(szTemp);
		return *this;
	}

	XStringTemplate& cat(double fValue, int nWidth = 0, BOOL bFillZero = false, int nDecimal = 0)
	{
		int			nRetCode	= 0;
		char_type	szFormat[8];
		char_type	szTemp[64];

		assert(nWidth >= 0);
		assert(nWidth < _countof(szTemp));

		nRetCode = snwprintf(
			szFormat, _countof(szFormat),
			L"%%%s%.0d%s%.0df", (bFillZero ? L"0" : L""), nWidth, (nDecimal > 0 ? L"." : L""), nDecimal
		);
		assert(nRetCode > 0);

		nRetCode = snwprintf(szTemp, _countof(szTemp), szFormat, fValue);
		assert(nRetCode > 0);

		append(szTemp);
		return *this;
	}

	XStringTemplate& cat(bool bValue, const char_type* pszTrue = NULL, const char_type* pszFalse = NULL)
	{
		int			nRetCode	= 0;
		char_type	szTemp[64];

		if (pszTrue == NULL)
			pszTrue = L"true";

		if (pszFalse == NULL)
			pszFalse = L"false";

		nRetCode = snwprintf(szTemp, _countof(szTemp), L"%s", (bValue ? pszTrue : pszFalse));
		assert(nRetCode > 0);

		append(szTemp);
		return *this;
	}

	XStringTemplate& cat(const char_type* pwszStr)
	{
		append(pwszStr);
		return *this;
	}

	XStringTemplate& operator += (XStringTemplate& other)
	{
		super_type::operator += (other.c_str());
		return *this;
	}

	template<typename U>
	XStringTemplate& operator +=(U value)
	{
		return cat(value);
	}
};

typedef XStringTemplate<char> xstring;
typedef XStringTemplate<wchar_t> xwstring;

